package com.example.myapplication.algorithm;

import android.util.Log;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class RespiratoryRateCalculator {
    private final static String TAG = "RespiratoryRateCalculator";
    private static RespiratoryRateCalculator INSTANCE;
    public synchronized static RespiratoryRateCalculator getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new RespiratoryRateCalculator();
        }
        return INSTANCE;
    }
    private final int requiredPeaks = 16; // 需要8个R峰来计算呼吸率
    private final int FR = 256; // 采样率256Hz
    private final double refractoryPeriodSec = 0.4; // R峰检测不应期(秒)
    private final int refractoryPeriodSamples = (int)(FR * refractoryPeriodSec);
    private Queue<Integer> rPeakTimestamps = new LinkedList<>(); // 存储R峰时间戳(样本索引)
    private Queue<Double> rPeakTimestampsValues = new LinkedList<>(); // 存储R峰时间戳(样本索引)
    private int lastPeakIndex = -refractoryPeriodSamples; // 上一个R峰位置
    private List<Double> ecgBuffer = new ArrayList<>(); // 存储ECG数据用于R峰检测
    public double resp = 0;
    // 定义简单的Pair类
    public class NumberPair {
        public Integer intValue;
        public Double doubleValue;
        public NumberPair(Integer intValue, Double doubleValue) {
            this.intValue = intValue;
            this.doubleValue = doubleValue;
        }
    }

    // 添加新的ECG数据并检测R峰
    public void addData(double ecgValue, int sampleIndex) {
        ecgBuffer.add(ecgValue);
        // 当缓冲区有足够数据时检测R峰
        if (ecgBuffer.size() >= FR * 2) { // 使用2秒窗口检测R峰
            List<NumberPair> peaks = findRPeaks(ecgBuffer);
            // 处理检测到的R峰
            for (NumberPair pair : peaks) {
                int peakIndex = pair.intValue;  // 获取 Integer 部分
                double peakValue = pair.doubleValue; // 获取 Double 部分

                int absolutePeakIndex = sampleIndex - ecgBuffer.size() + peakIndex;
                if (absolutePeakIndex > lastPeakIndex + refractoryPeriodSamples) {
                    rPeakTimestamps.offer(absolutePeakIndex);
                    rPeakTimestampsValues.offer(peakValue);
                    lastPeakIndex = absolutePeakIndex;
                    // 当收集到足够R峰时计算呼吸率
                    if (rPeakTimestamps.size() >= requiredPeaks) {
                        resp = findRespPeaks(rPeakTimestamps, rPeakTimestampsValues);
                        rPeakTimestamps.poll(); // 移除最旧的R峰
                        rPeakTimestampsValues.poll();
                    }
                }
            }
            // 保留最后1秒的数据以避免重复处理
            if (ecgBuffer.size() > FR) {
                ecgBuffer = new ArrayList<>(ecgBuffer.subList(ecgBuffer.size() - FR, ecgBuffer.size()));
            }
        }
    }

    /**
     * 寻找R峰
     * @param ecgData ECG数据列表
     * @return
     */
    private List<NumberPair> findRPeaks(List<Double> ecgData) {
        List<NumberPair> rPeakIndices = new ArrayList<>();
        if (ecgData.size() < 3)
            return rPeakIndices;

        // 计算动态阈值
        double threshold = 0.6 * getMaxValue(ecgData);

        // 寻找超过阈值的峰值
        for (int i = 1; i < ecgData.size() - 1; i++) {
            double current = ecgData.get(i);
            double prev = ecgData.get(i - 1);
            double next = ecgData.get(i + 1);
            // 简单的峰值检测
            if (current > prev && current > next && current > threshold) {
                // 检查不应期
                if (rPeakIndices.isEmpty() || (i - rPeakIndices.get(rPeakIndices.size() - 1).intValue) > refractoryPeriodSamples) {
                    rPeakIndices.add(new NumberPair(i, ecgData.get((i))));
                    // 动态调整阈值
                    threshold = 0.4 * threshold + 0.6 * current;
                }
            }
        }
        if (rPeakIndices.size() < 2) {
            Log.d("lzy", "R峰数量不足，无法计算心率");
        }
        // 计算RR间期（毫秒）
        double totalRRInterval = 0;
        for (int i = 1; i < rPeakIndices.size(); i++) {
            int rrInterval = rPeakIndices.get(i).intValue - rPeakIndices.get(i - 1).intValue;
            totalRRInterval += rrInterval;
        }
        double avgRRInterval = totalRRInterval / (rPeakIndices.size() - 1);
        // 转换为心率（次/分钟）
        double heartRate = (60.0 * FR) / avgRRInterval;
        Log.d("lzy", "计算的心率: " + heartRate + " 次/分钟");

        return rPeakIndices;
    }

    /**
     * 计算呼吸率
     * @param queue1 存储R峰时间戳的队列
     * @param queue2 存储R峰值的队列
     * @return
     */
    private double findRespPeaks(Queue<Integer> queue1, Queue<Double> queue2) {
        List<Integer> rPeakIndices = new ArrayList<>(queue1);
        List<Double> rPeakValues = new ArrayList<>(queue2);

        List<Integer> rPeakResult = new ArrayList<>();
        // 计算动态阈值
        double threshold = 0.6 * getMaxValue(rPeakValues);
        // 寻找超过阈值的峰值
        for (int i = 1; i < rPeakValues.size() - 1; i++) {
            double current = rPeakValues.get(i);
            double prev = rPeakValues.get(i - 1);
            double next = rPeakValues.get(i + 1);
            // 简单的峰值检测
            if (current > prev && current > next && current > threshold) {
                // 检查不应期
                {
                    rPeakResult.add(rPeakIndices.get(i));
                    // 动态调整阈值
                    threshold = 0.4 * threshold + 0.6 * current;
                }
            }
        }
        if (rPeakResult.size() < 2) {
            Log.d(TAG, "R峰数量不足，无法计算呼吸");
        }
        // 计算RR间期（毫秒）
        double totalRRInterval = 0;
        for (int i = 1; i < rPeakResult.size(); i++) {
            int rrInterval = rPeakResult.get(i) - rPeakResult.get(i - 1);
            totalRRInterval += rrInterval;
        }
        double avgRRInterval = totalRRInterval / (rPeakResult.size() - 1);
        double resp = (60.0 * FR) / avgRRInterval;
        resp = applyPhysiologicalConstraints(resp);
        return resp;
    }
    // 获取ECG数据中的最大值
    private double getMaxValue(List<Double> ecgData) {
        double max = Double.MIN_VALUE;
        for (double value : ecgData) {
            if (value > max) {
                max = value;
            }
        }
        return max;
    }
    /**
     * 应用成人静息状态下的呼吸率生理范围约束和变化率限制
     *
     * @param rate 原始呼吸率估计值
     * @param previousRate 前一次的呼吸率值
     * @return 约束后的呼吸率[6, 24] breaths/min，且与前一次相比变化不超过±2
     */
    public double previousRate = 12;
    private double applyPhysiologicalConstraints(double rate) {
        final double MIN_RESPIRATORY_RATE = 6.0;  // 成人静息最低呼吸率
        final double MAX_RESPIRATORY_RATE = 24.0; // 成人静息最高呼吸率
        final double MAX_CHANGE = 2.0; // 相邻两次呼吸率最大变化量
        // 先应用生理范围约束
        double constrainedRate = Math.max(MIN_RESPIRATORY_RATE, Math.min(MAX_RESPIRATORY_RATE, rate));
        // 再应用变化率限制
        if (previousRate >= MIN_RESPIRATORY_RATE && previousRate <= MAX_RESPIRATORY_RATE) {
            double lowerBound = Math.max(MIN_RESPIRATORY_RATE, previousRate - MAX_CHANGE);
            double upperBound = Math.min(MAX_RESPIRATORY_RATE, previousRate + MAX_CHANGE);
            constrainedRate = Math.max(lowerBound, Math.min(upperBound, constrainedRate));
            previousRate = constrainedRate;
        }
        return constrainedRate;
    }
}